/*
 * @Author: ygnnli 1585923072@qq.com
 * @Date: 2024-08-16 21:02:44
 * @LastEditors: ygnnli 1585923072@qq.com
 * @LastEditTime: 2024-08-27 22:36:43
 * @FilePath: /bitrpc/source/client/requestor.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#pragma once
#include "../common/net.hpp"
#include "../common/message.hpp"
#include <future>
#include <functional>

namespace bitrpc
{
    namespace client
    {
        class Requestor
        {
        public:
            using ptr = std::shared_ptr<Requestor>;
            using RequestCallback = std::function<void(const BaseMessage::ptr &)>;
            using AsyncResponse = std::future<BaseMessage::ptr>; // 异步响应
            // 请求描述
            struct RequestDescribe
            {
                using ptr = std::shared_ptr<RequestDescribe>;
                BaseMessage::ptr request; // 请求信息
                RType rtype;
                std::promise<BaseMessage::ptr> response; // 异步请求的响应结果
                RequestCallback callback;                // 响应的回调
            };
            // 响应处理
            void onResponse(const BaseConnection::ptr &conn, BaseMessage::ptr &msg)
            {
                std::string rid = msg->rid();
                RequestDescribe::ptr rdp = getDescribe(rid); // 获取请求描述
                if (rdp.get() == nullptr)
                {
                    ELOG("收到响应 - %s,但未找到对应的请求描述!", rid.c_str());
                    return;
                }
                // 如果是异步请求
                if (rdp->rtype == RType::REQ_ASYNC)
                {
                    rdp->response.set_value(msg); // 设置响应
                }
                // 如果是回调请求
                else if (rdp->rtype == RType::REQ_CALLBACK)
                {
                    if (rdp->callback)
                        rdp->callback(msg); // 调用回调
                }
                else
                {
                    ELOG("请求类型未知! !");
                }
                delDescribe(rid); // 处理完请求描述后删除
            }

            // 发送异步的请求
            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, AsyncResponse &async_rsp)
            {
                RequestDescribe::ptr rdp = newDescribe(req, RType::REQ_ASYNC); // 新增请求描述
                // rdp.get():获取指针
                if (rdp.get() == nullptr) // 如果构造请求描述失败
                {
                    ELOG("构造请求描述失败!");
                    return false;
                }
                conn->send(req);
                async_rsp = rdp->response.get_future(); // 获取响应
                return true;
            }

            // 发送同步的请求
            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, BaseMessage::ptr &rsp)
            {
                AsyncResponse rsp_future; // 异步响应
                bool ret = send(conn, req, rsp_future);
                if (ret == false)
                {
                    ELOG("发送同步请求失败!");
                    return false;
                }
                //ELOG("发送同步请求成功!");
                rsp = rsp_future.get(); // 获取响应
                //ELOG("获取响应成功!");
                return true;
            }
            
            // 发送回调的请求
            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, const RequestCallback &cb)
            {
                RequestDescribe::ptr rdp = newDescribe(req, RType::REQ_CALLBACK, cb); // 新增请求描述
                // rdp.get():获取指针
                if (rdp.get() == nullptr) // 如果构造请求描述失败
                {
                    ELOG("构造请求描述失败!");
                    return false;
                }
                conn->send(req); // 发送请求
                return true;
            }

        private:
            // 新增请求
            RequestDescribe::ptr newDescribe(const BaseMessage::ptr &req, RType rtype, const RequestCallback &cb = RequestCallback())
            {
                std::unique_lock<std::mutex> lock(_mutex);
                RequestDescribe::ptr rd = std::make_shared<RequestDescribe>(); // 请求描述
                rd->request = req;
                rd->rtype = rtype;
                if (rtype == RType::REQ_CALLBACK && cb) // 如果是回调请求且有回调函数
                {
                    rd->callback = cb;
                }
                // ELOG("新增请求!");
                _request_desc.insert(std::make_pair(req->rid(), rd));
                // ELOG("新增请求没问题!");
                return rd;
            }
            // 获取请求描述
            RequestDescribe::ptr getDescribe(const std::string &rid)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _request_desc.find(rid);
                if (it == _request_desc.end())
                {
                    return RequestDescribe::ptr();
                }
                return it->second;
            }
            // 删除请求描述
            void delDescribe(const std::string &rid)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _request_desc.erase(rid);
            }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string, RequestDescribe::ptr> _request_desc; // rid与请求描述的映射
        };
    }
}
